package com.example.test.dialogfactory;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.util.Pair;
import easier.log.logger.Logger;
import easier.webrtc.WebRtcManager;
import easier.webrtc.WebRtcManager.PeerSignalingBridge;
import easier.webrtc.WebRtcManager.SdpModel;
import io.socket.client.IO;
import io.socket.client.Socket;
import java.net.URISyntaxException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.List;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.json.JSONException;
import org.json.JSONObject;
import org.webrtc.CameraEnumerationAndroid.CaptureFormat;
import org.webrtc.CameraEnumerator;
import org.webrtc.EglBase;
import org.webrtc.IceCandidate;
import org.webrtc.SessionDescription;
import org.webrtc.SurfaceViewRenderer;
import org.webrtc.VideoTrack;

public class MainActivity86 extends AppCompatActivity {

    SurfaceViewRenderer localView;
    SurfaceViewRenderer remoteView;

    private SignalingClient mClient;

    public static void start( Context context ) {

        Intent starter = new Intent( context, MainActivity86.class );
        context.startActivity( starter );
    }

    @Override
    protected void onCreate( Bundle savedInstanceState ) {

        super.onCreate( savedInstanceState );
        setContentView( R.layout.activity_main86 );

        /* OpenGL ES */
        EglBase.Context eglBaseContext = EglBase.create().getEglBaseContext();

        localView = findViewById( R.id.local );
        localView.setMirror( true );
        localView.init( eglBaseContext, null );

        remoteView = findViewById( R.id.remote );
        remoteView.setMirror( false );
        remoteView.init( eglBaseContext, null );

        WebRtcManager manager = new WebRtcManager() {
            @Override
            public Pair< String, CaptureFormat > configVideoCapturer( CameraEnumerator cameraEnumerator,
                String[] deviceNames ) {

                /* 前置摄像头,分辨率小于等于480*640*30 */
                for ( String deviceName : deviceNames ) {
                    if ( cameraEnumerator.isFrontFacing( deviceName ) ) {
                        List< CaptureFormat > formats = cameraEnumerator.getSupportedFormats( deviceName );
                        for ( CaptureFormat format : formats ) {
                            if ( format.width <= 480 ) {
                                return new Pair<>( deviceName, format );
                            }
                        }
                        return new Pair<>( deviceName, formats.get( 0 ) );
                    }
                }

                /* 没有前置的摄像头,使用后置的 */
                for ( String deviceName : deviceNames ) {
                    if ( !cameraEnumerator.isFrontFacing( deviceName ) ) {
                        List< CaptureFormat > formats = cameraEnumerator.getSupportedFormats( deviceName );
                        return new Pair<>( deviceName, formats.get( 0 ) );
                    }
                }

                return null;
            }
        };

        manager.createMedia( this, localView );

        PeerSignalingBridge bridge = new PeerSignalingBridge() {
            @Override
            public void onOfferCreated( SdpModel offerData ) {

                Logger.i( "1.后加入房间的发送offer" );
                JSONObject jo = new JSONObject();
                try {
                    jo.put( "type", offerData.type );
                    jo.put( "sdp", offerData.sdp );

                    mClient.emit( "message", jo );
                } catch ( JSONException e ) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onAnswerCreated( SdpModel answerData ) {

                Logger.i( "2.先加入房间的收到offer,创建answer,发送answer" );
                JSONObject jo = new JSONObject();
                try {
                    jo.put( "type", answerData.type );
                    jo.put( "sdp", answerData.sdp );

                    mClient.emit( "message", jo );
                } catch ( JSONException e ) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onIceCandidateCreated( IceCandidate iceCandidate ) {

                Logger.i( "3.向对方发送IceCandidate" );
                JSONObject jo = new JSONObject();
                try {
                    jo.put( "type", "candidate" );
                    jo.put( "label", iceCandidate.sdpMLineIndex );
                    jo.put( "id", iceCandidate.sdpMid );
                    jo.put( "candidate", iceCandidate.sdp );

                    /* 发送给服务器转发,对面的客户端会受到回调SignalingClient#onIceCandidateReceived */
                    mClient.emit( "message", jo );
                } catch ( JSONException e ) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onVideoTrackReceived( VideoTrack remoteVideoTrack ) {

                Logger.i( "4.渲染对面数据到界面" );
                remoteView.post( new Runnable() {
                    @Override
                    public void run() {

                        remoteVideoTrack.addSink( remoteView );
                    }
                } );
            }
        };

        /* 创建信令客户端,连接信令服务器,信令发送 */
        mClient = new SignalingClient() {

            /**
             * 第一步:创建offer,并发送
             */
            @Override
            protected void onSelfJoined() {

                super.onSelfJoined();
                Logger.i( "1.后加入房间的创建offer" );
                bridge.createOffer();
            }

            @Override
            protected void onOfferReceived( JSONObject data ) {

                super.onOfferReceived( data );

                runOnUiThread( () -> {
                    Logger.i( "2.先加入房间的收到offer,创建answer" );
                    bridge.createAnswer( new SdpModel( SessionDescription.Type.OFFER.canonicalForm(), data.optString( "sdp" ) ) );
                } );
            }

            @Override
            protected void onAnswerReceived( JSONObject data ) {

                super.onAnswerReceived( data );
                Logger.i( "1.后加入房间的收到answer" );
                bridge.onAnswerReceived(
                    new SdpModel( SessionDescription.Type.ANSWER.canonicalForm(), data.optString( "sdp" ) ) );
            }

            @Override
            protected void onIceCandidateReceived( JSONObject data ) {

                super.onIceCandidateReceived( data );

                Logger.i( "3.收到对方发送IceCandidate" );
                IceCandidate iceCandidate = new IceCandidate(
                    data.optString( "id" ),
                    data.optInt( "label" ),
                    data.optString( "candidate" )
                );
                bridge.onIceCandidateReceived( iceCandidate );
            }
        };

        /* 创建p2p连接 */
        manager.createPeerConnection( bridge );
    }

    @Override
    protected void onDestroy() {

        super.onDestroy();
        mClient.close();
    }

    public static class SignalingClient {

        private static final String TAG = "SignalingClient";

        private final TrustManager[] trustAll = new TrustManager[]{
            new X509TrustManager() {
                @Override
                public void checkClientTrusted( X509Certificate[] chain, String authType ) throws CertificateException {

                }

                @Override
                public void checkServerTrusted( X509Certificate[] chain, String authType ) throws CertificateException {

                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {

                    return new X509Certificate[0];
                }
            }
        };

        private Socket socket;
        private String room = "NewPlace";

        public SignalingClient() {

            create();
        }

        protected void create() {

            try {
                /* 安全套接字协议实现 */
                SSLContext sslContext = SSLContext.getInstance( "TLS" );
                sslContext.init( null, trustAll, null );
                IO.setDefaultHostnameVerifier( ( hostname, session ) -> true );
                IO.setDefaultSSLContext( sslContext );

                socket = IO.socket( "https://192.168.0.106:8080" );
                socket.connect();

                /* 1.通知服务器创建房间 */
                socket.emit( "create or join", room );

                /* 2.已创建 */
                socket.on( "created", args -> {
                    //Log.e( TAG, "room created" );
                    onCreateRoom();
                } );
                /* 2.人已满 */
                socket.on( "full", args -> {
                    //Log.e( TAG, "room full" );
                } );
                /* 2.已加入 */
                socket.on( "join", args -> {
                    //Log.e( TAG, "peer joined" );
                    onPeerJoined();
                } );
                /* 2.已加入有人的房间 */
                socket.on( "joined", args -> {
                    //Log.e( TAG, "self joined" );
                    onSelfJoined();
                } );

                socket.on( "log", args -> {
                    //Log.e( TAG, "log call " + Arrays.toString( args ) );
                } );

                /* 4.断开服务器连接 */
                socket.on( "bye", args -> {
                    //Log.e( TAG, "bye " + args[0] );
                    onPeerLeave( (String) args[0] );
                } );

                /* 3.通信,收到消息 */
                socket.on( "message", args -> {
                    //Log.e( TAG, "message " + Arrays.toString( args ) );
                    Object arg = args[0];
                    if ( arg instanceof String ) {

                    } else if ( arg instanceof JSONObject ) {
                        JSONObject data = (JSONObject) arg;
                        String type = data.optString( "type" );
                        if ( "offer".equals( type ) ) {
                            onOfferReceived( data );
                        } else if ( "answer".equals( type ) ) {
                            onAnswerReceived( data );
                        } else if ( "candidate".equals( type ) ) {
                            onIceCandidateReceived( data );
                        }
                    }
                } );

            } catch ( NoSuchAlgorithmException | URISyntaxException | KeyManagementException e ) {
                e.printStackTrace();
            }
        }

        public void emit( String event, Object args ) {

            if ( socket != null ) {
                socket.emit( event, args );
            }
        }

        protected void onSelfJoined() {

        }

        protected void onPeerLeave( String arg ) {

        }

        protected void onOfferReceived( JSONObject data ) {

        }

        protected void onAnswerReceived( JSONObject data ) {

        }

        protected void onIceCandidateReceived( JSONObject data ) {

        }

        protected void onPeerJoined() {

        }

        protected void onCreateRoom() {

        }

        public void close() {

            if ( socket != null ) {
                if ( socket.connected() ) {
                    socket.disconnect();
                }
                socket.close();
                socket = null;
            }
        }
    }
}